#include "String.h"

namespace MiniWindow
{
	String::String()
	{
		this->_value = null;
		this->_capacity = 0;
	}
	String::String(int capacity)
	{
		this->_value = null;
		this->_capacity = capacity;
		this->_value = new tchar[this->_capacity + 1];
		memset(this->_value, 0, sizeof(tchar)*(this->_capacity + 1));
	}
	String::String(const tchar * string)
	{
		this->_value = null;
		this->_capacity = 0;
		if (null != string)
		{
			this->_capacity = lstrlen(string);
			this->_value = new tchar[this->_capacity + 1];
			lstrcpy(this->_value, string);
		}
	}
	String::String(const tchar * string, int length)
	{
		this->_value = null;
		this->_capacity = 0;
		if (null != string)
		{
			this->_capacity = length;
			this->_value = new tchar[this->_capacity + 1];
			memcpy(this->_value, string, sizeof(tchar)*length);
		}
	}
	String::~String()
	{
		if (!this->IsReferenced())
		{
			delete this->_value;
		}
		this->_value = null;
		this->_capacity = 0;
	}

	int String::Length() const
	{
		if (null == this->_value)
		{
			return 0;
		}
		return lstrlen(this->_value);
	}
	int String::Capacity() const
	{
		return this->_capacity;
	}

	String::operator tchar *() const
	{
		return this->_value;
	}

	bool String::operator==(const tchar* string) const
	{
		if (null == this->_value && null == string)
		{
			return true;
		}
		return 0 == lstrcmp(this->_value, string);
	}
	bool String::operator!=(const tchar* string) const
	{
		if (null == this->_value && null == string)
		{
			return false;
		}
		return 0 != lstrcmp(this->_value, string);
	}
	bool String::operator==(const String& string) const
	{
		return this->operator==(string._value);
	}
	bool String::operator!=(const String& string) const
	{
		return this->operator!=(string._value);
	}
	String String::operator+(const String& string) const
	{
		String result(this->Length() + string.Length());
		result += *this;
		result += string;
		return result;
	}
	String& String::operator=(const String& string)
	{
		if (this->IsReferenced(string))
		{
			return *this;
		}
		if (!this->IsReferenced())
		{
			delete this->_value;
		}
		this->_value = string._value;
		this->_capacity = string._capacity;
		SharedObject::operator=(string);
		return *this;
	}
	String& String::operator+=(const String& string)
	{
		bool referenced = this->IsReferenced();
		if (null == string._value)
		{
			if (referenced)
			{
				this->DetachReference();
				this->AttachReference();
			}
			return *this;
		}
		this->DetachReference();
		int length = lstrlen(string._value);
		int slength = (null == this->_value ? 0 : lstrlen(this->_value));
		int alllength = length + slength;
		if (!referenced
			&&
			null != this->_value
			&&
			this->_capacity >= alllength
			)
		{
			memset(this->_value + slength, 0, sizeof(tchar)*(this->_capacity - slength + 1));
			lstrcpy(this->_value + slength, string._value);
		}
		else
		{
			tchar * value = new tchar[alllength + 1];
			lstrcpy(value, this->_value);
			lstrcpy(value + slength, string._value);
			if (!referenced)
			{
				delete this->_value;
			}
			this->_value = value;
			this->_capacity = alllength;
		}
		this->AttachReference();
		return *this;
	}
	String String::operator+(const tchar* string) const
	{
		String result(this->Length() + (null == string ? 0 : lstrlen(string)));
		result += *this;
		result += string;
		return result;
	}
	String& String::operator=(const tchar* string)
	{
		bool referenced = this->IsReferenced();
		this->DetachReference();
		if (null == string)
		{
			if (!referenced)
			{
				delete this->_value;
			}
			this->_value = null;
			this->_capacity = 0;
		}
		else
		{
			int length = lstrlen(string);
			if (!referenced && (this->_capacity >= length))
			{
				memset(this->_value, 0, sizeof(tchar)*(this->_capacity + 1));
				lstrcpy(this->_value, string);
			}
			else
			{
				if (!referenced)
				{
					delete this->_value;
				}
				this->_capacity = length;
				this->_value = new tchar[length + 1];
				lstrcpy(this->_value, string);
			}
		}
		this->AttachReference();
		return *this;
	}
	String& String::operator+=(const tchar* string)
	{
		bool referenced = this->IsReferenced();
		if (null == string)
		{
			if (referenced)
			{
				this->DetachReference();
				this->AttachReference();
			}
			return *this;
		}
		this->DetachReference();
		int length = lstrlen(string);
		int slength = (null == this->_value ? 0 : lstrlen(this->_value));
		int alllength = length + slength;
		if (!referenced
			&&
			null != this->_value
			&&
			this->_capacity >= alllength
			)
		{
			memset(this->_value + slength, 0, sizeof(tchar)*(this->_capacity - slength + 1));
			lstrcpy(this->_value + slength, string);
		}
		else
		{
			tchar * value = new tchar[alllength + 1];
			lstrcpy(value, this->_value);
			lstrcpy(value + slength, string);
			if (!referenced)
			{
				delete this->_value;
			}
			this->_value = value;
			this->_capacity = alllength;
		}
		this->AttachReference();
		return *this;
	}

	int String::IndexOf(const tchar* string) const
	{
		if (
			null == this->_value
			||
			null == string
			)
		{
			return -1;
		}
		int tlen = lstrlen(string);
		int slen = lstrlen(this->_value);
		if (tlen > slen)
		{
			return -1;
		}
		for (int i = 0; i < slen; ++i)
		{
			if (*(this->_value + i) == *(string))
			{
				bool checked = true;
				for (int j = 0; j < tlen; ++j)
				{
					if (*(this->_value + i + j) != *(string + j))
					{
						checked = false; break;
					}
				}
				if (checked)
				{
					return i;
				}
			}
		}
		return -1;
	}

	int String::LastIndexOf(const tchar* string) const
	{
		if (
			null == this->_value
			||
			null == string
			)
		{
			return -1;
		}
		int tlen = lstrlen(string);
		int slen = lstrlen(this->_value);
		if (tlen > slen)
		{
			return -1;
		}
		for (int i = slen - tlen - 1; i > -1; --i)
		{
			if (*(this->_value + i) == *(string))
			{
				bool checked = true;
				for (int j = 0; j < tlen; ++j)
				{
					if (*(this->_value + i + j) != *(string + j))
					{
						checked = false; break;
					}
				}
				if (checked)
				{
					return i;
				}
			}
		}
		return -1;
	}
	String String::Substring(int index) const
	{
		if (index > this->Length() - 1)
		{
			return null;
		}
		return String(this->_value + index);
	}
	String String::Substring(int index, int length) const
	{
		if ((index + length) > this->Length() - 1)
		{
			return null;
		}
		return String((this->_value + index), length);
	}

	bool String::IsNullOrEmpty(const tchar* string)
	{
		return (null == string || lstrlen(string) < 1);
	}
	bool String::IsNullOrWhiteSpace(const tchar* string)
	{
		if (null == string)
		{
			return true;
		}
		int length = lstrlen(string);
		if (length < 1)
		{
			return true;
		}
		for (int i = 0; i < length; ++i)
		{
			if (*(string + i) != TEXT(' '))
			{
				return false;
			}
		}
		return true;
	}
}